package org.rpgmapper.bo;

import java.util.EnumMap;
import org.rpgmapper.bo.rules.Rule;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.rpgmapper.bo.rules.CoreRules;

public class Character {

    private long id;
    private String name;
    private int side;
    private List<Weapon> weapons = new ArrayList<Weapon>();
    private Map<Stat, Integer> stats = new EnumMap<Stat, Integer>(Stat.class);
    private Map<Stat, Integer> modifiers = new EnumMap<Stat, Integer>(Stat.class);
    private List<Bonus> bonus = new ArrayList<Bonus>();
    private List<Rule> ruleSet = new ArrayList<Rule>();
    private List<StatChangeListener> listeners = new ArrayList<StatChangeListener>();

    public Character(long id, String name) {
        this();
        this.id = id;
        this.name = name;
    }

    public Character() {
        ruleSet.add(CoreRules.get());
        setBase(Stat.Str, 10);
        setBase(Stat.Dex, 10);
        setBase(Stat.Con, 10);
        setBase(Stat.Int, 10);
        setBase(Stat.Wis, 10);
        setBase(Stat.Cha, 10);
    }

    @Override
    public String toString() {
        String s = "Character : " + "id=" + id + ", name=" + name + ", side=" + side + "\n";
        for (Stat stat : stats.keySet()) {
            s += stat + " : " + get(stat) + "\n";
        }
        for (Stat stat : modifiers.keySet()) {
            if (!stats.containsKey(stat)) {
                s += stat + " : " + get(stat) + "\n";
            }
        }

        return s;
    }

    public void copyTo(Character c) {
        if (c != null) {
            c.setId(this.getId());
            c.setName(this.getName());
            c.setSide(this.getSide());
            c.stats.putAll(stats);
            c.ruleSet.addAll(ruleSet);
        }
    }

    public void refreshRuleSet() {


        for (Stat stat : modifiers.keySet()) {
            setMod(stat, 0);
        }

        for (Rule rule : ruleSet) {
            rule.apply(this);
        }

    }

    public List<Bonus> getBonus() {
        return bonus;
    }

    public void setBonus(List<Bonus> bonus) {
        this.bonus = bonus;
    }

    public final void setBase(Stat stat, int value) {
        stats.put(stat, value);
        for (StatChangeListener listener : listeners) {
            listener.onBaseStatChange(this, stat);
            listener.onStatChange(this, stat);
        }
    }

    public void setMod(Stat stat, int value) {
        modifiers.put(stat, value);
        for (StatChangeListener listener : listeners) {
            listener.onModifierChange(this, stat);
            listener.onStatChange(this, stat);
        }
    }

    /**
     * returns the modifier value of the stat
     * @param stat
     * @return 
     */
    public int getMod(Stat stat) {
        Integer v = modifiers.get(stat);
        return v == null ? 0 : v;
    }

    /**
     * returns the list of modifiers    
     * @return 
     */
    public Map<Stat, Integer> getModifiers() {
        return modifiers;
    }

    /**
     * returns the list of bases stats    
     * @return 
     */
    public Map<Stat, Integer> getBases() {
        return stats;
    }

    /**
     * returns the base value of the stat
     * @param stat
     * @return 
     */
    public int getBase(Stat stat) {
        Integer v = stats.get(stat);
        return v == null ? 0 : v;
    }

    /**
     * returns the actual value of the stat (base + mod)
     * @param stat
     * @return 
     */
    public int get(Stat stat) {
        return getBase(stat) + getMod(stat);
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void addRules(List<Rule> rules) {
        ruleSet.addAll(rules);
    }

    public void addRule(Rule rule) {
        ruleSet.add(rule);
    }

    public int getSide() {
        return side;
    }

    public void setSide(int side) {
        this.side = side;
    }

    public List<Weapon> getWeapons() {
        return weapons;
    }

    public void setWeapons(List<Weapon> weapons) {
        this.weapons = weapons;
    }

    public void addStatChangeListener(StatChangeListener l) {
        listeners.add(l);
    }

    public void removeStatChangeListener(StatChangeListener l) {
        listeners.remove(l);
    }

}
